#pragma once
#include<src/math/functor/GaussianFunctor.h>
#include<src/data/ParticleSet.h>
#include <src/math/BoundaryCondition/BoundaryCondition.h>

template <class data, std::size_t Dim = data::Dim> 
struct norm_test_fill_data
{
	data operator()()
	{
		OS_STATIC_CHECK(false); // you have to implement this test
	};
};

template <class data> 
struct norm_test_fill_data<data,1>
{
	data operator()()
	{
		return 	InverseCumulativeFunctor<data>()(10);
	};
};

template <class data> 
struct norm_test_fill_data<data,2> 
{
	data operator()() 
	{
		return 	InverseCumulativeFunctor<data>()(10,3);
	};
};
template<class data>
struct norm_data_example {
	particle<OS_double> operator () () {
		std::cout << std::endl << " ---------------------------------------------------" << std::endl;
		std::cout << std::endl << " --------norm_data_example-------" << std::endl;

		data gaussian = norm_test_fill_data<data>()();
		data gaussian_1 = -gaussian;
		std::cout << std::endl << " Consider a 10 point gaussian vector (gaussian) and its inverse (gaussian_1 = - gaussian)" << std::endl;
		std::cout << std::endl << " we compute " << std::endl;

		particle<OS_double> result(8);

		result[0] = jmmath::distance(gaussian,gaussian_1);
		std::cout << std::endl << " distance(gaussian,gaussian_1) " << result[0];
		OS_double test = jmmath::norm2(2.*gaussian);
		OS_double test_2 = jmmath::norm2(gaussian);
		bool logical = test == result[0];
		logical &= 2.*test_2 == result[0];
		OS_DYNAMIC_CHECK(logical == true, "norm_data_example : problem with distance");

		data::value_type r_moment_1_ = jmmath::moment1(gaussian);
		result[1]	= jmmath::norm1(r_moment_1_);
		std::cout << std::endl << " norm_1(moment1(gaussian)) " << result[1];
		result[2]	= jmmath::moment2(gaussian);
		std::cout << std::endl << " moment2(gaussian) " << result[2];
		result[3]	= jmmath::norm1(gaussian);
		std::cout << std::endl << " norm1(gaussian) " << result[3];
		result[4]	= jmmath::norm2(gaussian);
		std::cout << std::endl << " norm2(gaussian) " << result[4];
		result[5]	= jmmath::norm_infty(gaussian);
		std::cout << std::endl << " norm_infty(gaussian) " << result[5];
		result[6]	= jmmath::normed_scalar_prod(gaussian,gaussian_1);
		std::cout << std::endl << " normed_scalar_prod(gaussian,gaussian_1) " << result[6];
		result[7]	= jmmath::scalar_prod(gaussian,gaussian_1);
		std::cout << std::endl << " ---------------------------------------------------" << std::endl;
		std::cout << std::endl << " --------end norm_data_example. returning the results-------" << std::endl;

		return result;
	}
};

template <class data1,class data2>
void norm_compare (){

		std::cout << std::endl << " ---------------------------------------------------" << std::endl;
		std::cout << std::endl << " --------Starting norm_example-------" << std::endl;
		particle<OS_double> p_mod1 = norm_data_example<data1>()();
		particle<OS_double> p_mod2 = norm_data_example<data2>()();
		double breakpoint1 = jmmath::norm22(p_mod1-p_mod2);
		double breakpoint2 = jmmath::norm22(p_mod1);
		bool logical = (breakpoint1/breakpoint2) < THRESHOLD;

		OS_DYNAMIC_CHECK(logical == true, "norm_example breakpoint 1: norms depends on data definition");

		std::cout << std::endl << " -------Ending Cauchy_examples-----" << std::endl;
		std::cout << std::endl << " ---------------------------------------------------" << std::endl;

  };

void norm_test();
